#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <unistd.h>
#include <sys/select.h>
#include <fcntl.h>

#define MYPORT 10001
#define MAXLINE 1024

//发送缓冲区比较小的时候，fgets之后需要多次回车才能完整显示内容
//如果使用重定向进行批量输入，会导入收到的回复少于发送的内容，因为过早关闭了描述符
//需要用shutdown关闭写端,以及更改为针对缓冲区操作，不用fgets和fputs

void str_cli(FILE* fp, int sockfd){
    int maxfdp1;
    fd_set rset;
    char sendline[MAXLINE], recvline[MAXLINE];
    int stdineof = 0;
    
    FD_ZERO(&rset);
    while(1){
        if(stdineof == 0){
            FD_SET(fileno(fp), &rset);
        }
        FD_SET(sockfd, &rset);
        maxfdp1 = fileno(fp) > sockfd ? fileno(fp) : sockfd;
        maxfdp1++;

        select(maxfdp1, &rset, NULL, NULL, NULL);
        int n;
        if(FD_ISSET(sockfd, &rset)){
            if((n = read(sockfd, recvline, MAXLINE)) < 0){
                perror("read()");
                exit(1);
            }
            else if(n == 0){
                if(stdineof == 1){
                    return;
                }
                else{
                    fprintf(stderr, "server close\n");
                    exit(2);
                }
            }
            else{
                write(fileno(stdout), recvline, n);
            }
        }

        if(FD_ISSET(fileno(fp), &rset)){
            if((n = read(fileno(fp), sendline, MAXLINE)) == 0){
                //close(sockfd);
                stdineof = 1;
                shutdown(sockfd, SHUT_WR);
                FD_CLR(fileno(fp), &rset);
                continue;
            }
            write(sockfd, sendline, n);
        }
    }
}

int main(int argc, char** argv){
    int sock_fd;
    struct sockaddr_in seraddr;
    if(argc != 2){
        printf("usage: simple_client <IPaddress>\n");
        return 1;
    }

    sock_fd = socket(AF_INET, SOCK_STREAM, 0);
    memset(&seraddr, 0, sizeof(seraddr));
    seraddr.sin_family = AF_INET;
    seraddr.sin_port = htons(MYPORT);
    if(inet_pton(AF_INET, argv[1], &seraddr.sin_addr) < 0){
        perror("inet_pton()");
    }

    connect(sock_fd, (struct sockaddr*)&seraddr, sizeof(seraddr));
    str_cli(stdin, sock_fd);
    return 0;
}